/****************************************************************************
 * Copyright (C) 2009-2010 SciTouch LLC
 * 
 * This file is part of Indigo toolkit.
 * 
 * This file may be distributed and/or modified under the terms of the
 * GNU General Public License version 3 as published by the Free Software
 * Foundation and appearing in the file LICENSE.GPL included in the
 * packaging of this file.
 * 
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 ***************************************************************************/

#ifndef __molecule_arom_h__
#define __molecule_arom_h__

#include "graph/cycle_enumerator.h"

class Molecule;

// Aromatization classes
class AromatizerBase
{
public:
   explicit AromatizerBase (const Molecule &molecule);
   virtual ~AromatizerBase ();

   void aromatize ();
   void reset     (void);

   bool isBondAromatic      (int e_idx);
   const byte* isBondAromaticArray (void);

   void addAromaticCycle    (int id, const int *cycle, int cycle_len);
   void removeAromaticCycle (int id, const int *cycle, int cycle_len);
   bool handleUnsureCycles  ();

   void setBondAromaticCount (int e_idx, int count);

protected:
   // Functions for overloading
   virtual bool _checkVertex         (int v_idx);
   virtual bool _isCycleAromatic     (const int *cycle, int cycle_len);
   virtual void _handleAromaticCycle (const int *cycle, int cycle_len);

protected:

   enum { MAX_CYCLE_LEN = 22 };

   struct CycleDef
   {
      int   id;
      bool  isEmpty;
      int   length;
      int   cycle[MAX_CYCLE_LEN];
   };

   const Molecule &_molecule;

   TL_CP_DECL(Array<byte>,      _bonds_arom);
   TL_CP_DECL(Array<int>,       _bonds_arom_count);
   TL_CP_DECL(Array<CycleDef>,  _unsure_cycles);

   bool _checkDoubleBonds     (const int *cycle, int cycle_len);
   void _aromatizeCycle       (const int *cycle, int cycle_len);
   void _handleCycle          (const Array<int> &vertices);

   static bool _cb_check_vertex (const Graph &graph, int v_idx, void *context);
   static bool _cb_handle_cycle (const Graph &graph, const Array<int> &vertices, const Array<int> &edges, void *context);

   int _cyclesHandled;
   int _unsureCyclesCount;
};

class MoleculeAromatizer : public AromatizerBase
{
public:
   // Interface function for aromatization
   static void aromatizeBonds (Molecule &mol);

   explicit MoleculeAromatizer (const Molecule &molecule);
   void precalculatePiLabels ();

   static void findAromaticAtoms (const Molecule &mol, Array<int> *atoms, Array<int> *bonds, bool allow_arom);

protected:
   virtual bool _checkVertex      (int v_idx);
   virtual bool _isCycleAromatic  (const int *cycle, int cycle_len);

   int _getPiLabel (int v_idx);
   TL_CP_DECL(Array<int>, _pi_labels);
};

class QueryMoleculeAromatizer : public AromatizerBase
{
public:
   // Interface function for query molecule aromatization
   static void aromatizeBonds (Molecule &mol);

   enum { EXACT, FUZZY };

   explicit QueryMoleculeAromatizer (const Molecule &molecule);

   // RET: false if number of cycles is too big
   bool enumerateMolecules   ();

   void setMode              (int mode);
   void precalculatePiLabels ();

   void *context;
   bool (*cb_handle_molecule_aromatization) (const Molecule &molecule, void *context);
   bool (*cb_check_cycles_count)            (int count, void *context);

protected:
   struct PiValue 
   {
      PiValue () {}
      PiValue (int min, int max, int exact = -1) : min(min), max(max), exact(exact) {}

      int min, max; 
      int exact;
   };

   virtual bool _checkVertex         (int v_idx);
   virtual bool _isCycleAromatic     (const int *cycle, int cycle_len);
   virtual void _handleAromaticCycle (const int *cycle, int cycle_len);

   static void _aromatizeBondsExact (Molecule &mol);
   static void _aromatizeBondsFuzzy (Molecule &mol);

   static void _aromatizeRGroupFragment (Molecule &fragment);

   PiValue _getPiLabel           (int v_idx);

   TL_CP_DECL(Array<PiValue>,   _pi_labels);
   TL_CP_DECL(Array<CycleDef>,  _aromatic_cycles);
   TL_CP_DECL(Molecule,    _result_molecule);

   DEF_ERROR("query_aromatizer");

   int _mode;
   bool _collecting;
};


#endif
